home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ETO Development Tools 4
/
ETO Development Tools 4.iso
/
Tools - Objects
/
MacApp
/
MacApp 2.0.1
/
MacApp CD Release
/
MacApp 2.0.1 (Hard Disk Ready)
/
Libraries
/
UMacAppUtilities.inc1.p
< prev
next >
Wrap
Text File
|
1990-10-25
|
75KB
|
2,872 lines
{$P}
{[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]}
{UMacAppUtilities.inc1.p}
{Copyright © 1984-1990 Apple Computer, Inc. All rights reserved.}
{ These are utilities. Treat them like language extensions. }
{$W+}
{$R-}
{$Init-}
{$OV-}
{$IFC qNames}
{$D+}
{$ENDC}
{--------------------------------------------------------------------------------------------------}
{ The debugger uses some of this unit's
types in it's interface so we must use
externals. !!! Resolve this. }
TYPE
DebugForceOptions = (forceOn, forceOff, forceUnchanged);
VAR
{$Push} {$J+}
GWORKPORT: GrafPtr; { Found in UMacApp.p }
{$Pop}
FUNCTION DebugCanReadLn: Boolean;
EXTERNAL;
FUNCTION DebugCanWriteLn: Boolean;
EXTERNAL;
PROCEDURE DebugEndForce;
EXTERNAL;
PROCEDURE ProgramBreak(grievance: Str255);
EXTERNAL;
PROCEDURE DebugForceOutput(ToWindow, ToFile: DebugForceOptions);
EXTERNAL;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
PROCEDURE BlockSet(destPtr: Ptr;
byteCount: longint;
setVal: UNIV SignedByte);
{ ??? should be improved to do longword setting. }
VAR
endPtr: Ptr;
BEGIN
destPtr := Ptr(StripLong(destPtr));
endPtr := Ptr(Ord(destPtr) + byteCount);
WHILE Ord(destPtr) < Ord(endPtr) DO
BEGIN
destPtr^ := setVal;
destPtr := Ptr(Ord(destPtr) + 1);
END;
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
FUNCTION CanWriteLn: Boolean;
BEGIN
{$IFC qDebug}
CanWriteLn := DebugCanWriteLn;
{$ELSEC}
CanWriteLn := FALSE;
{$ENDC}
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
FUNCTION CanReadLn: Boolean;
BEGIN
{$IFC qDebug}
CanReadLn := DebugCanReadLn;
{$ELSEC}
CanReadLn := FALSE;
{$ENDC}
END;
{--------------------------------------------------------------------------------------------------}
{$Push}
{$MC68020-} { Need to be able to alert user if this
isn't a 68020 machine }
{$S MAUtilitiesRes} { This must always be in a resident segment
as aRect may be within a handle }
PROCEDURE CenterRectOnScreen(VAR aRect: Rect;
horizontally, vertically, forDialog: Boolean);
VAR
screenSize: Point;
rectSize: Point;
newSize: INTEGER;
BEGIN
{ Calculate screen size minus menu bar }
WITH screenBits.bounds DO
SetPt(screenSize, right - left, bottom - top - gMBarHeight);
{ ??? should we use the same algorithm
as in TWindow.GetMaxIntersectedDevice }
WITH aRect DO
BEGIN
SetPt(rectSize, right - left, bottom - top);
IF horizontally THEN
left := (screenSize.h - rectSize.h) DIV 2;
IF vertically THEN
IF forDialog THEN
BEGIN
newSize := (screenSize.v - rectSize.v) DIV 5;
top := Max(newSize, 10) + gMBarHeight;
END
ELSE
top := (screenSize.v - rectSize.v) DIV 2;
right := left + rectSize.h;
bottom := top + rectSize.v;
END;
END;
{$Pop}
{--------------------------------------------------------------------------------------------------}
{$S MAFile}
FUNCTION CloseFile(dataRefnum, rsrcRefnum: INTEGER): OSErr;
VAR
err: OSErr;
BEGIN
err := noErr;
IF dataRefnum <> kNoFileRefnum THEN
err := FSClose(dataRefnum);
IF rsrcRefnum <> kNoFileRefnum THEN
BEGIN
CloseResFile(rsrcRefnum);
IF err = noErr THEN
err := ResError;
END;
CloseFile := err;
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
FUNCTION CompareStrings(first, second: Str255): INTEGER;
{$IFC NOT qNeedsROM128k}
EXTERNAL;
{$ELSEC}
BEGIN
CompareStrings := RelString(first, second, TRUE, TRUE);
END;
{$ENDC}
{--------------------------------------------------------------------------------------------------}
{$Push}
{$MC68020-}
{$S MAUtilitiesRes}
FUNCTION ConcatNumber(aString: Str255;
aNumber: longint): Str255;
VAR
numberString: Str255;
BEGIN
NumToString(aNumber, numberString);
ConcatNumber := CONCAT(aString, numberString);
END;
{$Pop}
{--------------------------------------------------------------------------------------------------}
{$S MAFields}
PROCEDURE ConfigRecFields(aTitle: Str255;
VAR aConfigRec: ConfigRecord;
PROCEDURE DoToField(fieldName: Str255;
fieldAddr: Ptr;
fieldType: INTEGER));
CONST
envSE30 = 7; { Not in the MPW 3.0 interfaces }
VAR
aString: Str255;
BEGIN
DoToField(aTitle, NIL, bTitle);
DoToField(' environsVersion', @aConfigRec.environsVersion, bInteger);
CASE aConfigRec.machineType OF
envMac:
aString := 'envMac';
envXL:
aString := 'envXL';
envMachUnknown:
aString := 'envMachUnknown';
env512KE:
aString := 'env512KE';
envMacPlus:
aString := 'envMacPlus';
envSE:
aString := 'envSE';
envMacII:
aString := 'envMacII';
envMacIIx:
aString := 'envMacIIx';
envSE30:
aString := 'envSE30';
OTHERWISE
aString := 'envMachUnknown';
END;
DoToField(' machineType', @aString, bString);
DoToField(' systemVersion', @aConfigRec.systemVersion, bHexInteger);
CASE aConfigRec.processor OF
envCPUUnknown:
aString := 'envCPUUnknown';
env68000:
aString := 'env68000';
env68010:
aString := 'env68010';
env68020:
aString := 'env68020';
env68030:
aString := 'env68030';
OTHERWISE
aString := 'envCPUUnknown';
END;
DoToField(' processor', @aString, bString);
DoToField(' hasFPU', @aConfigRec.hasFPU, bBoolean);
DoToField(' hasColorQD', @aConfigRec.hasColorQD, bBoolean);
CASE aConfigRec.keyboardType OF
envUnknownKbd:
aString := 'envUnknownKbd';
envMacKbd:
aString := 'envMacKbd';
envMacAndPad:
aString := 'envMacAndPad';
envMacPlusKbd:
aString := 'envMacPlusKbd';
envAExtendKbd:
aString := 'envAExtendKbd';
envStandADBKbd:
aString := 'envStandADBKbd';
OTHERWISE
aString := 'envUnknownKbd';
END;
DoToField(' keyboardType', @aString, bString);
DoToField(' atDrvrVersNum', @aConfigRec.atDrvrVersNum, bInteger);
DoToField(' sysVRefNum', @aConfigRec.sysVRefNum, bInteger);
DoToField(' hasROM128K', @aConfigRec.hasROM128K, bBoolean);
DoToField(' hasHFS', @aConfigRec.hasHFS, bBoolean);
DoToField(' hasHierarchicalMenus', @aConfigRec.hasHierarchicalMenus, bBoolean);
DoToField(' hasScriptManager', @aConfigRec.hasScriptManager, bBoolean);
DoToField(' hasStyleTextEdit', @aConfigRec.hasStyleTextEdit, bBoolean);
DoToField(' hasSoundManager', @aConfigRec.hasSoundManager, bBoolean);
DoToField(' hasWaitNextEvent', @aConfigRec.hasWaitNextEvent, bBoolean);
DoToField(' hasSCSI', @aConfigRec.hasSCSI, bBoolean);
DoToField(' hasDesktopBus', @aConfigRec.hasDesktopBus, bBoolean);
DoToField(' hasAUX', @aConfigRec.hasAUX, bBoolean);
DoToField(' hasTempMem', @aConfigRec.hasTempMem, bBoolean);
DoToField(' has32BitQD', @aConfigRec.has32BitQD, bBoolean);
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
PROCEDURE CopyStr255(VAR fmStr: Str255;
toAddr: UNIV Ptr);
BEGIN
BlockMove(@fmStr, toAddr, LENGTH(fmStr) + 1);
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
PROCEDURE DefaultSize(VAR theSize: INTEGER);
BEGIN
IF qNeedsScriptManager | gConfiguration.hasScriptManager THEN
BEGIN
IF theSize = GetDefFontSize THEN
theSize := 0;
END
ELSE IF qNeedsROM128K | gConfiguration.hasROM128K THEN
BEGIN
IF (theSize = IntegerPtr(kLMSysFontSize)^) THEN
theSize := 0;
END
ELSE IF theSize = 12 THEN { Guess }
theSize := 0;
END;
{--------------------------------------------------------------------------------------------------}
{$S MAFile}
FUNCTION DeleteFile(namePtr: StringPtr;
volRefnum: INTEGER): OSErr;
VAR
hPB: HParamBlockRec;
err: OSErr;
BEGIN
WITH hPB DO
BEGIN
ioNamePtr := namePtr;
ioVRefnum := volRefnum;
ioFVersNum := 0;
END;
err := FillInDirID(@hPB); {to avoid PMSP}
IF err = noErr THEN
err := PBHDelete(@hPB, FALSE);
DeleteFile := err;
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
PROCEDURE DisposIfHandle(aHandle: UNIV Handle);
BEGIN
aHandle := DisposeIfHandle(aHandle);
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
FUNCTION DisposeIfHandle(aHandle: UNIV Handle): Handle;
CONST
resourceBit = 5;
initVal = $D3; { odd at all byte boundaries }
VAR
handleBits: SignedByte;
BEGIN
DisposeIfHandle := NIL; { For convenience of caller }
IF aHandle <> NIL THEN
BEGIN
IF qDebug THEN
BEGIN
{ Test handlehood }
IF IsHandle(aHandle) THEN
BEGIN
handleBits := GetHandleBits(aHandle);
IF MemError <> noErr THEN
BEGIN
WriteLn('Handle was so bad I couldn''t even get the handle bits!');
WrLblHexLongint('Bad Handle', longint(aHandle));
WriteLn;
ProgramBreak('');
END
ELSE IF IsHandlePurged(aHandle) THEN { h might have been purged }
BEGIN
DisposHandle(aHandle);
END
ELSE IF BTST(handleBits, resourceBit) THEN
BEGIN
WriteLn('Trying to dispose a resource handle');
WrLblHexLongint('Bad Handle', longint(aHandle));
WriteLn;
ProgramBreak('');
END
ELSE
BEGIN
{ Set the handle contents to a real nice value for any dangling pointerciples }
BlockSet(aHandle^, GetHandleSize(aHandle), initVal);
DisposHandle(aHandle);
END;
END
ELSE
BEGIN
IF VerboseIsHandle(aHandle) THEN; { Get the diagnosis printed }
WriteLn('Trying to dispose an invalid handle');
WrLblHexLongint('Bad Handle', longint(aHandle));
WriteLn;
ProgramBreak('');
END;
END
ELSE
DisposHandle(aHandle);
END;
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
PROCEDURE DisposIfPtr(aPtr: UNIV Ptr);
BEGIN
aPtr := DisposeIfPtr(aPtr);
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
FUNCTION DisposeIfPtr(aPtr: UNIV Ptr): Ptr;
CONST
resourceBit = 5;
initVal = $D5; { odd at all byte boundaries }
BEGIN
DisposeIfPtr := NIL; { For convenience of caller }
IF aPtr <> NIL THEN
BEGIN
IF qDebug THEN
BEGIN
{ Test pointerhood, ??? Shouldn't we have a real test here? }
IF (NOT Odd(Ord(aPtr))) THEN
BEGIN
BlockSet(aPtr, GetPtrSize(aPtr), initVal);
DisposPtr(aPtr);
END
ELSE
BEGIN
WriteLn('Trying to dispose an invalid pointer');
WrLblHexLongint('Bad Pointer', longint(aPtr));
WriteLn;
ProgramBreak('');
END;
END
ELSE
DisposPtr(aPtr);
aPtr := NIL;
END;
END;
{--------------------------------------------------------------------------------------------------}
FUNCTION EqualBlocks(first, second: UNIV Ptr;
theSize: INTEGER): Boolean;
EXTERNAL;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
PROCEDURE EachWMgrWindowDo(PROCEDURE DoToWMgrWindow(theWMgrWindow: WindowPtr));
VAR
aWindowPtr: WindowPtr;
BEGIN
aWindowPtr := GetWindowList;
WHILE (aWindowPtr <> NIL) DO
BEGIN
IF (aWindowPtr <> gWorkPort) THEN { ignore the work window }
DoToWMgrWindow(aWindowPtr);
aWindowPtr := WindowPtr(WindowPeek(aWindowPtr)^.nextWindow);
END;
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
FUNCTION FindWindowBefore(theWindow: WindowPtr): WindowPtr;
{ returns the window just before a given window. Returns nil if the given window is frontmost or
not found. }
PROCEDURE DoToWMgrWindow(theWMgrWindow: WindowPtr);
BEGIN
IF WindowPtr(WindowPeek(theWMgrWindow)^.nextWindow) = theWindow THEN
BEGIN
FindWindowBefore := theWMgrWindow;
exit(FindWindowBefore);
END;
END;
BEGIN
FindWindowBefore := NIL;
EachWMgrWindowDo(DoToWMgrWindow);
END;
{--------------------------------------------------------------------------------------------------}
{$S MAFile}
FUNCTION FileModDate(name: Str255;
volRefnum: INTEGER): longint;
VAR
pb: HParamBlockRec;
BEGIN
IF GetFileInfo(name, volRefnum, pb) = noErr THEN
FileModDate := pb.ioFlMdDat
ELSE
FileModDate := 0;
END;
{--------------------------------------------------------------------------------------------------}
PROCEDURE FieldToString(theData: Ptr;
fieldType: INTEGER;
VAR theString: Str255);
EXTERNAL;
{--------------------------------------------------------------------------------------------------}
{$S MAFile}
FUNCTION FillInDirID(pb: HParmBlkPtr): OSErr;
BEGIN
FillInDirID := GetDirID(pb^.ioVRefnum, pb^.ioDirID);
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
FUNCTION GetActualJustification(justification: INTEGER): INTEGER;
BEGIN
IF justification = teJustSystem THEN { actually teJustLeft }
BEGIN
IF qNeedsScriptManager | gConfiguration.hasScriptManager THEN
GetActualJustification := GetSysJust
ELSE IF qNeedsROM128K | gConfiguration.hasROM128K THEN
GetActualJustification := IntegerPtr(kLMTESysJust)^
ELSE
GetActualJustification := teJustLeft;
END
ELSE
GetActualJustification := justification;
END;
{--------------------------------------------------------------------------------------------------}
{$S MAFile}
FUNCTION GetDirID(VAR vRefnum: INTEGER;
VAR dirID: longint): OSErr;
VAR
pb: WDPBRec;
BEGIN
IF qNeedsROM128K | gConfiguration.hasHFS THEN
BEGIN
WITH pb DO
BEGIN
ioNamePtr := NIL;
ioVRefnum := vRefnum;
ioWDIndex := 0;
ioWDProcID := 0;
ioWDVRefnum := vRefnum;
END;
GetDirID := PBGetWDInfo(@pb, FALSE);
vRefnum := pb.ioWDVRefnum;
dirID := pb.ioWDDirID;
END
ELSE
BEGIN
dirID := 0;
GetDirID := noErr;
END;
END;
{--------------------------------------------------------------------------------------------------}
{$S MAFile}
FUNCTION GetFileInfo(name: Str255;
volRefnum: INTEGER;
VAR info: HParamBlockRec): OSErr;
VAR
err: OSErr;
BEGIN
WITH info DO
BEGIN
ioNamePtr := @name;
ioVRefnum := volRefnum;
ioFVersNum := 0;
ioFDirIndex := 0;
END;
err := FillInDirID(@info);
IF err = noErr THEN
err := PBHGetFInfo(@info, FALSE);
GetFileInfo := err;
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
FUNCTION GetFontNum(fontName: Str255): INTEGER;
VAR
fontNum: INTEGER;
BEGIN
UprString(fontName, FALSE);
IF fontName = kSysFontName THEN
BEGIN
IF qNeedsScriptManager | gConfiguration.hasScriptManager THEN
fontNum := GetSysFont
ELSE
fontNum := systemFont;
END
ELSE IF fontName = kApplFontName THEN
BEGIN
IF qNeedsScriptManager | gConfiguration.hasScriptManager THEN
fontNum := GetAppFont
ELSE
fontNum := applFont;
END
ELSE
GetFNum(fontName, fontNum);
GetFontNum := fontNum;
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes} {Must be in Main segment and cannot call to
any other segment.}
FUNCTION GetHandleBits(h: Handle): SignedByte;
CONST
MemErr = $220; {[GLOBAL VAR] last memory manager error [word]}
BEGIN
IF qNeedsROM128K | gConfiguration.hasROM128K THEN
GetHandleBits := HGetState(h)
ELSE
BEGIN
IntegerPtr(MemErr)^ := noErr;
IF (h=nil) THEN
GetHandleBits := 0
ELSE
GetHandleBits := SignedBytePtr(h)^;
END;
END;
{--------------------------------------------------------------------------------------------------}
{$IFC NOT qNeedsColorQD} { Becomes an inline if we know the machine
has color QD }
{$S MAUtilitiesRes}
PROCEDURE GetIfBkColor(VAR aColor: RGBColor);
CONST
BlackBit = 5;
YellowBit = 6;
MagentaBit = 7;
CyanBit = 8;
VAR
oldColor: longint;
BEGIN
IF qNeedsColorQD | gConfiguration.hasColorQD THEN
GetBackColor(aColor)
ELSE
BEGIN { Map old, dumb CMYB system to RGB color }
{[f-]}
(* xxxxxxx C.MY B rgb w b = RGB
blackColor = 33 = 0000000 0.00 1 000 0 1 = 000
whiteColor = 30 = 0000000 0.00 0 111 1 0 = 111
redColor = 205 = 0000000 0.11 0 011 0 1 = 100
greenColor = 341 = 0000000 1.01 0 101 0 1 = 010
blueColor = 409 = 0000000 1.10 0 110 0 1 = 001
cyanColor = 273 = 0000000 1.00 0 100 0 1 = 011
magentaColor = 137 = 0000000 0.10 0 010 0 1 = 101
yellowColor = 69 = 0000000 0.01 0 001 0 1 = 110
*)
{[f+]}
oldColor := thePort^.bkColor; { Fetch old color }
aColor := gRGBBlack; { Prime returned color to black }
IF BTST(oldColor, BlackBit) THEN { If color isn't black, force CMY = 111 }
oldColor := BOR(oldColor, $1C0);
IF NOT BTST(oldColor, CyanBit) THEN { Absence of cyan = presence of red }
aColor.red := $FFFF;
IF NOT BTST(oldColor, MagentaBit) THEN { Absence of magenta = presence of green }
aColor.green := $FFFF;
IF NOT BTST(oldColor, YellowBit) THEN { Absence of yellow = presence of blue }
aColor.blue := $FFFF;
END;
END;
{$ENDC}
{--------------------------------------------------------------------------------------------------}
{$IFC NOT qNeedsColorQD} { Becomes an inline if we know the machine
has color QD }
{$S MAUtilitiesRes}
PROCEDURE GetIfColor(VAR aColor: RGBColor);
CONST
BlackBit = 5;
YellowBit = 6;
MagentaBit = 7;
CyanBit = 8;
VAR
oldColor: longint;
BEGIN
IF qNeedsColorQD | gConfiguration.hasColorQD THEN
GetForeColor(aColor)
ELSE
BEGIN { Map old, dumb CMYB system to RGB color }
{ xxxxxxx C.MY B rgb w b = RGB
blackColor = 33 = 0000000 0.00 1 000 0 1 = 000
whiteColor = 30 = 0000000 0.00 0 111 1 0 = 111
redColor = 205 = 0000000 0.11 0 011 0 1 = 100
greenColor = 341 = 0000000 1.01 0 101 0 1 = 010
blueColor = 409 = 0000000 1.10 0 110 0 1 = 001
cyanColor = 273 = 0000000 1.00 0 100 0 1 = 011
magentaColor = 137 = 0000000 0.10 0 010 0 1 = 101
yellowColor = 69 = 0000000 0.01 0 001 0 1 = 110
}
oldColor := thePort^.fgColor; { Fetch old color }
aColor := gRGBBlack; { Prime returned color to black }
IF BTST(oldColor, BlackBit) THEN { If color isn't black, force CMY = 111 }
oldColor := BOR(oldColor, $1C0);
IF NOT BTST(oldColor, CyanBit) THEN { Absence of cyan = presence of red }
aColor.red := $FFFF;
IF NOT BTST(oldColor, MagentaBit) THEN { Absence of magenta = presence of green }
aColor.green := $FFFF;
IF NOT BTST(oldColor, YellowBit) THEN { Absence of yellow = presence of blue }
aColor.blue := $FFFF;
END;
END;
{$ENDC}
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
PROCEDURE GetPortFontInfo(fontNum: INTEGER;
VAR fontName: Str255;
VAR fontSize: INTEGER);
BEGIN
IF (fontNum = systemFont) | ((qNeedsROM128K | gConfiguration.hasROM128K) & (
(qNeedsScriptManager | gConfiguration.hasScriptManager) & (fontNum = GetSysFont)) |
(fontNum = IntegerPtr(kLMSysFontFam)^)) THEN
BEGIN
fontName := kSysFontName;
DefaultSize(fontSize);
END
ELSE IF (fontNum = applFont) | (((qNeedsScriptManager | gConfiguration.hasScriptManager) &
(fontNum = GetAppFont)) | (fontNum = IntegerPtr(kLMApFontID)^)) THEN
BEGIN
fontName := kApplFontName;
DefaultSize(fontSize);
END
ELSE
GetFontName(fontNum, fontName);
END;
{--------------------------------------------------------------------------------------------------}
{$Push}
{$MC68020-}
{$S Main}
PROCEDURE LockHandleHigh(h: Handle);
BEGIN
IF h <> NIL THEN
BEGIN
IF qDebug & NOT IsHandle(h) THEN
BEGIN
IF VerboseIsHandle(h) THEN; { Get the diagnosis printed }
ProgramBreak('In LockHandleHigh: not handed a handle');
END
ELSE
BEGIN
MoveHHi(h); { ??? check MemErr ??? }
HLock(h);
END;
END;
END;
{$Pop}
{--------------------------------------------------------------------------------------------------}
{$Push}
{$MC68020-}
{$S MAUtilitiesRes}
FUNCTION GetTrapType(theTrap: INTEGER): TrapType;
BEGIN
{ OS traps start with A0, Tool with A8 or AA. }
IF BAND(theTrap, $0800) = 0 THEN { per D.A }
GetTrapType := OSTrap
ELSE
GetTrapType := ToolTrap;
END;
{$Pop}
{--------------------------------------------------------------------------------------------------}
{ Nothing in this procedure can be allowed to fail }
{$Push}
{$MC68020-}
{$S MAMiniInit}
PROCEDURE DoRealInitToolBox;
VAR
aCursHandle: CursHandle;
BEGIN
InitGraf(@thePort);
InitFonts;
InitWindows; { creates non-relocatable for the WM port }
{ _DON'T_ flush disk-inserted or MultiFinder™ events or you'll be sorry! }
FlushEvents(everyEvent - diskMask - app4Mask, 0);
InitMenus;
TEInit;
InitDialogs(NIL);
aCursHandle := GetCursor(watchCursor); { Watch should be in system file, but just
in case… }
InitCursor; { !!! This forces an arrow cursor. Is there
a way to reset the show/hide level and
init all the cursor goo without having
this visual glitch? ( the Finder™ sets the
cursor to a watch when launching. It would
be nice to stay that way until the app is
ready for events. }
IF aCursHandle <> NIL THEN
SetCursor(aCursHandle^^); { Change cursor to watch }
{$IFC qDebug} { Enable pre and postcondition testing }
gPreCondition := TRUE;
gPostCondition := TRUE;
{$ENDC}
{ Find out just what kind of environment we're dealing with here }
DefineConfiguration(gConfiguration);
{ Init the stuff that MATextBox uses }
gMATextBoxTE := NIL;
gTEDefaultWordBreak := NIL;
SetRGBColor(gRGBBlack, 0, 0, 0);
SetRGBColor(gRGBWhite, $FFFF, $FFFF, $FFFF);
{ -1 = $FFFFFFFF, the largest 32 bit address. Our routine StripLong uses a pre-stripped
address gStrippedAddress to avoid the yucky MPW glue. }
gStrippedAddress := StripAddress(Ptr( - 1));
{ !!! I hate to have to allocate this memory here. Is there a better way to encapsulate
this and defer the allocation until later. Many routines touch the region (Even after
InvalidateCursor was implemented) }
gCursorRgn := NewRgn; { Hope it doesn't fail. Really isn't likely
to though. }
{ Ensure that the following tests for the script manager or 128K ROM are *always* performed
since we may have launched on a non-script manager Mac or a non-128K Mac *even*
if app is built with -NeedsScriptManager or -NeedsROM128K }
IF {qNeedsScriptManager |} gConfiguration.hasScriptManager THEN
gMBarHeight := GetMBarHeight
ELSE IF {qNeedsROM128K |} gConfiguration.hasROM128K THEN
gMBarHeight := GetLMMBarHeight
ELSE
gMBarHeight := 20; { Guess }
{$IFC qDebug OR qInspector}
gFieldToStrRtn := @StdFieldToString;
{$EndC}
gBoolString[TRUE] := 'TRUE';
gBoolString[FALSE] := 'FALSE';
gDeadStripSuppression := FALSE;
gCreateWithTemplates := gDeadStripSuppression; { for compatibility with Dave W. class notes
}
{ The refnum where the application's resources should be found }
gApplicationRefNum := CurResFile;
gToolBoxInitialized := TRUE;
END;
{$Pop}
{--------------------------------------------------------------------------------------------------}
{ Nothing in this procedure can be allowed to fail }
{$Push}
{$MC68020-}
{$S Main} { This procedure is intended to be in "Main"
which is already loaded }
PROCEDURE _DataInit; { Routine in the A5 globals initializer }
EXTERNAL;
PROCEDURE InitToolBox;
CONST
kBreathingRoom = 1024; { Amount of heap space needed for init }
VAR
h: Handle;
PROCEDURE FailedInitToolBox;
BEGIN
IF qDebug THEN
DebugStr('Not enough room to init ToolBox Managers');
ExitToShell; {??? any good way to signal this to the user
???}
END;
BEGIN
{ the heap and stack don't overlap. So there's enough room to init the managers.
Make sure that the MAMiniInit Segment can be loaded and that there's still a little
Room after that. }
UnloadSeg(@_DataInit); { Toss some ballast }
{ "MAMain" this is MacApp's own code that must be resident… even before/during the UMemory startup.
GetNamedResource will call RsrvMem which locates the handle as low in memory as possible.
We will then lock it there… just like "Main"}
SetResLoad(FALSE);
h := GetNamedResource('CODE', 'MAMain');
SetResLoad(TRUE);
IF (h <> NIL) THEN
ResrvMem(SizeResource(h));
h := GetNamedResource('CODE', 'MAMain');
IF (h <> NIL) THEN
HLock(h)
ELSE
FailedInitToolBox;
h := GetNamedResource('CODE', 'MAMiniInit');
IF (h <> NIL) THEN
HLock(h)
ELSE
FailedInitToolBox;
{ Attempt to ensure that there is going to be kBreathingRoom bytes available in the heap so that
when the actual toolbox managers are initialized there is a significantly reduced chance that
they will express their displeasure with us through SysErr -25 or -2. If the space is not
currently available in the zone as shown by FreeMem then attempting to allocate it will let
growzoneproc operate and grow the zone a little, as necessary. If, after that, we haven't been
able to get the breathing room we desire then just give up and fade silently away. (Like the old
soldier, not the old executive). }
IF FreeMem >= kBreathingRoom THEN
DoRealInitToolBox
ELSE
BEGIN
h := NewHandle(kBreathingRoom);
IF h <> NIL THEN { get the grow space }
BEGIN
DisposHandle(h);
DoRealInitToolBox;
END
ELSE
FailedInitToolBox; { Give up }
END;
END;
{$Pop}
{--------------------------------------------------------------------------------------------------}
{ Nothing in this procedure can be allowed to fail }
{$Push}
{$MC68020-}
{$S MAMiniInit}
FUNCTION ValidateConfiguration(configuration: ConfigRecord): Boolean;
VAR
isSupported: Boolean;
BEGIN
{ Run the gauntlet of support tests using the conditionally set constants.
If any single test fails then the app is considered unsupported on this machine. }
isSupported := TRUE;
IF qNeedsScriptManager THEN
isSupported := isSupported & configuration.hasScriptManager;
IF qNeedsROM128K THEN
isSupported := isSupported & configuration.hasROM128K;
IF qNeedsHierarchicalMenus THEN
isSupported := isSupported & configuration.hasHierarchicalMenus;
IF qNeedsStyleTextEdit THEN
isSupported := isSupported & configuration.hasStyleTextEdit;
IF qNeedsWaitNextEvent THEN
isSupported := isSupported & configuration.hasWaitNextEvent;
IF qNeedsColorQD THEN
isSupported := isSupported & configuration.hasColorQD;
IF qNeedsMC68020 THEN
isSupported := isSupported & ((configuration.processor <> env68000) &
(configuration.processor <> env68010));
IF qNeedsMC68030 THEN
isSupported := isSupported & ((configuration.processor <> env68000) &
(configuration.processor <> env68010) & (configuration.processor <>
env68020));
IF qNeedsFPU THEN
isSupported := isSupported & configuration.hasFPU;
{ skanky hack under A/UX to ensure that all app's are pulled to front early on }
IF configuration.hasAUX THEN
PullApplicationToFront;
ValidateConfiguration := isSupported;
END;
{$Pop}
{--------------------------------------------------------------------------------------------------}
{ Nothing in this procedure can be allowed to fail }
{$Push}
{$MC68020-}
{$S MAMiniInit}
PROCEDURE DefineConfiguration(VAR configuration: ConfigRecord);
CONST
{Masks for the HwCfgFlags}
mSCSIPort = $8000;
mDesktopBus = $0400;
mHasAUX = $0200;
{ Test that DTS says is OK for 32 bit QD. It is an internal trap that is only implemented
if QD32 is installed. }
_MA32BitQD = $AB03;
VAR
kludge: ^SysEnvRec;
result: OSErr;
BEGIN
kludge := @configuration;
result := SysEnvirons(1, kludge^); {Version 1 shouldn't fail}
WITH configuration DO
BEGIN
hasDesktopBus := BAND(GetHwCfgFlags, mDesktopBus) > 0;
hasSCSI := BAND(GetHwCfgFlags, mSCSIPort) > 0;
hasAUX := BAND(GetHwCfgFlags, mHasAUX) > 0;
hasROM128K := machineType > envMac;
IF hasROM128K THEN
hasHFS := TRUE
ELSE
hasHFS := GetFSFCBLen > 0;
hasHierarchicalMenus := hasROM128K & TrapExists(_PopUpMenuSelect);
hasScriptManager := hasROM128K & TrapExists(_ScriptUtil);
hasStyleTextEdit := systemVersion >= $600;
hasSoundManager := hasROM128K & TrapExists(_SndDoCommand);
hasWaitNextEvent := hasROM128K & TrapExists(_WaitNextEvent);
hasTempMem := TrapExists(_OSDispatch);
has32BitQD := TrapExists(_MA32BitQD);
END;
END;
{$Pop}
{--------------------------------------------------------------------------------------------------}
{ Nothing in this procedure can be allowed to fail }
{$Push}
{$MC68020-}
{$S Main} { Must be in main segment as it is called in
early initialization AND in MacAppAlert }
PROCEDURE PullApplicationToFront;
VAR
theEvent: EventRecord;
i: INTEGER;
BEGIN
{ The "Programmer's guide to MultiFinder™ says make an event call several times.
I guess 3 calls counts as several. Also, it says call GetNextEvent but we don't
want to lose events on the floor so we use EventAvail since it seems to work OK }
FOR i := 1 TO 3 DO
IF EventAvail(everyEvent, theEvent) THEN;
END;
{$Pop}
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
FUNCTION IsFreeHandle(h: UNIV Handle): Boolean;
{ Walk the free-list looking for the given handle }
VAR
applZone: THz;
currHandle: Handle;
BEGIN
IsFreeHandle := FALSE;
applZone := ApplicZone;
currHandle := Handle(applZone^.hFstFree);
WHILE (currHandle <> NIL) DO
BEGIN
IF currHandle = h THEN
BEGIN
IsFreeHandle := TRUE;
LEAVE;
END;
currHandle := Handle(currHandle^);
END;
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
FUNCTION TestRecoverHandle(masterPointer: Ptr;
h: UNIV Handle): Boolean;
{ TestRecoverHandle determines if the given masterPointer recovers via RecoverHandle to be the given
handle h. Since RecoverHandle fails if h is from a heap other than the current heap, we need to set
the zone to be the handle's zone before calling RecoverHandle. }
{$IFC FALSE}
VAR
itsZone, { the handle's zone }
currentZone: THz; { the current zone (don't assume ApplicZone)
}
restoreZone: Boolean; { flag whether to restore zone }
{$ENDC}
BEGIN
{$IFC FALSE}
TestRecoverHandle := FALSE;
{ Test handle's Zone - if it comes from a different zone, then RecoverHandle won't work,
in that case, set the current zone to be the handle's zone }
itsZone := HandleZone(h); { get the handle's zone }
IF MemError = noErr THEN
BEGIN
currentZone := GetZone; { get the current zone }
IF itsZone = currentZone THEN { Are zones the same? }
restoreZone := FALSE { …yes, so set flag to not restore }
ELSE
BEGIN
restoreZone := TRUE; { …no, so set flag to restore zone }
SetZone(itsZone); { and set the zone to be the handle's zone }
END;
TestRecoverHandle := RecoverHandle(masterPointer) = Handle(h);
IF restoreZone THEN { restore the zone if the flag is set }
SetZone(currentZone);
END;
{$ENDC}
{ This function doesn't work correctly, so we set it to return true. The old code is left
in for reference. }
TestRecoverHandle := TRUE;
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
FUNCTION IsHandle(h: UNIV Handle): Boolean;
{ Returns true if handle appears valid. }
VAR
masterPointer: Ptr;
BEGIN
IsHandle := FALSE;
IF
{ Test handle NILness }
(h <> NIL)
{ Test handle Oddness }
& NOT Odd(Ord(h)) THEN
BEGIN
masterPointer := Ptr(StripLong(h^));
IsHandle :=
{ Test master pointer Oddness }
(NOT Odd(Ord(masterPointer)))
{ Not Purged… does it recover? }
& (((masterPointer <> NIL) & (TestRecoverHandle(masterPointer, h)))
{ Purged }
| (masterPointer = NIL));
END;
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
FUNCTION IsHandleLocked(h: UNIV Handle): Boolean;
{ Returns lockState of h. }
CONST
lockBit = 7;
VAR
handleBits: SignedByte;
BEGIN
handleBits := GetHandleBits(h);
IF MemError <> noErr THEN { h might have been purged }
IsHandleLocked := FALSE
ELSE
IsHandleLocked := BTST(handleBits, lockBit);
END;
{--------------------------------------------------------------------------------------------------}
{$IFC qDebug}
{$S MAUtilitiesRes}
FUNCTION IsHandlePurged(h: UNIV Handle): Boolean;
{ Returns purgeState of h. }
BEGIN
IF qDebug & NOT IsHandle(h) THEN
BEGIN
IF VerboseIsHandle(h) THEN; { Get the diagnosis printed }
ProgramBreak('IsHandlePurged was not handed a handle, pretty handy, eh?');
IsHandlePurged := TRUE; { !!! What is a decent result. shouldn't
developer just signal failure from the
debugger. We need to force the issue }
END
ELSE
IsHandlePurged := h^ = NIL;
END;
{$EndC}
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
FUNCTION LengthRect(r: Rect;
vhs: VHSelect): INTEGER;
BEGIN
WITH r DO
LengthRect := botRight.vh[vhs] - topLeft.vh[vhs];
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
FUNCTION LongerSide(VAR r: Rect): VHSelect;
BEGIN
WITH r DO
IF (bottom - top) >= (right - left) THEN
LongerSide := v
ELSE
LongerSide := h;
END;
{--------------------------------------------------------------------------------------------------}
{$S MADebug}
PROCEDURE LIntToHex(decNumber: UNIV longint;
VAR hexNumber: String8;
noOfDigits: INTEGER);
VAR
i: INTEGER;
BEGIN
noOfDigits := Min(noOfDigits, 8);
hexNumber[0] := CHR(noOfDigits);
FOR i := noOfDigits DOWNTO 1 DO
BEGIN
hexNumber[i] := kHexDigits[BAND(decNumber, 15) + 1];
decNumber := BSR(decNumber, 4);
END;
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
FUNCTION LowerChar(ch: CHAR): CHAR;
BEGIN
IF (ch >= 'A') & (ch <= 'Z') THEN
LowerChar := CHR(Ord(ch) + 32)
ELSE
LowerChar := ch;
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
PROCEDURE LowerStr255(VAR s: Str255);
VAR
i: INTEGER;
BEGIN
FOR i := 1 TO LENGTH(s) DO
IF (s[i] IN ['A'..'Z']) THEN
s[i] := CHR(Ord(s[i]) + 32)
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
FUNCTION MAUseResFile(refNum: INTEGER): INTEGER;
{ UseResFile the newResFile and return the old CurResFile. }
BEGIN
MAUseResFile := CurResFile;
UseResFile(refNum);
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
FUNCTION MinMax(MinVal, expression, MaxVal: longint): longint;
{Returns the bounded minimum and maximum }
BEGIN
MinMax := Min(Max(expression, MinVal), MaxVal);
END;
{--------------------------------------------------------------------------------------------------}
{$S MADebug}
PROCEDURE NumberToHex(theNumber: UNIV longint;
VAR hexString: Str255;
hexDigits: INTEGER);
VAR
tempString: String8;
BEGIN
LIntToHex(theNumber, tempString, hexDigits);
hexString := CONCAT('$', tempString);
END;
{--------------------------------------------------------------------------------------------------}
{$S MADebug}
PROCEDURE PointerToHex(theNumber: UNIV longint;
VAR hexString: Str255;
hexDigits: INTEGER);
VAR
tempString: String8;
BEGIN
IF theNumber = 0 THEN
hexString := 'Nil'
ELSE
BEGIN
LIntToHex(StripLong(theNumber), tempString, hexDigits);
hexString := CONCAT('$', tempString);
END;
END;
{--------------------------------------------------------------------------------------------------}
{$S MAFile}
FUNCTION NumBlocks(numBytes: longint;
blkSize: longint): longint;
BEGIN
NumBlocks := (numBytes + blkSize - 1) DIV blkSize;
END;
{--------------------------------------------------------------------------------------------------}
{$S MAFile}
FUNCTION MAOpenFile(name: Str255;
volRefnum: INTEGER;
openData, openRsrc: Boolean;
dataPerm, rsrcPerm: INTEGER;
VAR dataRefnum, rsrcRefnum: INTEGER): OSErr;
VAR
pb: HParamBlockRec;
oldVRefnum: INTEGER;
result: OSErr;
PROCEDURE TestForError(err: OSErr);
BEGIN
IF err <> noErr THEN
BEGIN
MAOpenFile := err;
exit(MAOpenFile);
END;
END;
BEGIN
{always open data fork, to establish that the file does exist}
WITH pb DO
BEGIN
ioNamePtr := @name;
ioVRefnum := volRefnum;
ioVersNum := 0;
ioPermssn := dataPerm;
ioMisc := NIL;
END;
TestForError(FillInDirID(@pb));
IF qNeedsROM128K | gConfiguration.hasHFS THEN
result := PBHOpenDeny(@pb, FALSE) { Try the shared volume open. }
ELSE
result := paramErr;
IF result = paramErr THEN { Not on a shared volume, try HFS open. }
BEGIN
pb.ioPermssn := BAND(dataPerm, 3);
result := PBHOpen(@pb, FALSE);
END;
TestForError(result);
IF openData THEN
dataRefnum := pb.ioRefnum
ELSE
BEGIN
{ we did not want the data fork open, so close it now }
TestForError(FSClose(pb.ioRefnum));
dataRefnum := kNoFileRefnum;
END;
IF openRsrc THEN
BEGIN
IF qNeedsROM128K | gConfiguration.hasROM128K THEN
BEGIN
rsrcRefnum := OpenRFPerm(name, volRefnum, BAND(rsrcPerm, 7));
result := ResError;
END
ELSE
BEGIN
TestForError(GetVol(NIL, oldVRefnum));
TestForError(SetVol(NIL, volRefnum));
rsrcRefnum := OpenResFile(name);
TestForError(SetVol(NIL, oldVRefnum));
END;
IF result <> noErr THEN
rsrcRefnum := kNoFileRefnum;
TestForError(result);
END
ELSE
rsrcRefnum := kNoFileRefnum;
MAOpenFile := noErr;
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
VAR
pSaveHText: Handle;
pMATextBoxHText: Handle;
{$Push}
{$IFC qTrace} {$D+} {$ENDC}
PROCEDURE StdNoRect(verb: GrafVerb;
r: Rect);
{ StdNoRect filters out the rect drawing calls. }
BEGIN
END;
{$Pop}
PROCEDURE MATextBox(text: Ptr;
itsLength: longint;
box: Rect;
itsJust: INTEGER;
autoWrap: Boolean;
wordBreak: ProcPtr;
eraseFirst: Boolean;
spaceForCaret: Boolean);
CONST
kTextBoxCaretSlopSize = 1; { Since TextBox uses TE to image the text,
we may need to adjust by 1 pixel. Reason:
TE draws beginning 1 pixel to the right to
allow for the insertion point (which we
won't have since this is drawn text, not
editable text).}
kMaxTEChars = 32000; { Actually TE suffers some other limitations
as well. Such as misbehaviour and or
bombing when the sum of the lineheights >
32k or a linewidth > 32k (overflows
QuickDraw space) But these are _MUCH_ more
difficult to test for in a quick way }
kOurMaxHandleSize = 256; { our Max handle size }
VAR
fInfo: FontInfo;
savedHText: Handle;
sysJust: INTEGER;
{ these next two locals eat up lots of stack space...this could be improved by allocating
a pointer for the one that is used (eg allocate a pointer for myCQDProcs if CDQ available) }
myQDProcs: QDProcs;
myCQDProcs: CQDProcs;
hadQDProcs: BOOLEAN;
saveRectProc: ProcPtr;
PROCEDURE InitMyPrivateTE;
CONST
kZoneHeader = 52; { 52 bytes for header }
kZoneTrailer = 12; { 12 bytes for trailer }
kMPBlockHeader = 8; { 8 bytes for Master Pointer block hdr }
kInitialMstrPtrs = 2; { 2 master pointers created initially }
kSlop = 32; { bytes of slop (just in case) }
kZoneOverhead = kZoneHeader + kZoneTrailer + kMPBlockHeader +
4 * kInitialMstrPtrs + kSlop; { how large the zone overhead is }
VAR
aTEZonePtr: Ptr;
startPtr: Ptr;
BEGIN
pMATextBoxHText := NIL;
gMATextBoxTE := TENew(box, box);
IF (gMATextBoxTE = NIL) THEN { can't allocate space for our terecord }
exit(InitMyPrivateTE);
{ • save off several items of interest }
WITH gMATextBoxTE^^ DO
BEGIN
gTEDefaultWordBreak := wordBreak;
pSaveHText := hText; { save the text handle }
END;
{ • Since TESetText (called near the end of MATextBox) hits the heap, we can speed this hit
to the heap for small text lengths (<= 255), by allocating a special text handle in its own
separate heap. We'll use this text handle whenever the text length is <= 255. }
{ • create a separate heap }
aTEZonePtr := NewPtr(kOurMaxHandleSize + kZoneOverhead);
IF (aTEZonePtr = NIL) THEN { can't allocate space for our heap }
exit(InitMyPrivateTE);
startPtr := Ptr(StripLong(aTEZonePtr));
InitZone(NIL, kInitialMstrPtrs, Ptr(Ord(startPtr) + GetPtrSize(aTEZonePtr)), startPtr);
{ • InitZone sets the current zone to the newly created zone }
{ • allocate our new text handle in our new heap zone }
pMATextBoxHText := NewHandle(kOurMaxHandleSize); { the text handle }
{ • restore the heap zone }
SetZone(ApplicZone);
END;
FUNCTION IsColorPort(aGrafPtr: GrafPtr): BOOLEAN;
BEGIN
IsColorPort := (qNeedsColorQD | gConfiguration.hasColorQD)
& (BAND(CGrafPtr(aGrafPtr)^.portVersion, $C000) = $0000C000) { 2 hi bits. IM V pp. 49-50 }
END;
BEGIN
{ Create my goodies if necessary }
IF gMATextBoxTE = NIL THEN
BEGIN
InitMyPrivateTE;
IF gMATextBoxTE = NIL THEN { couldn't allocate the TE handle }
BEGIN
TextBox(text, itsLength, box, itsJust); { default to TextBox in low memory }
exit(MATextBox);
END;
END;
{ Setup the work TE with the necessary parameters }
GetFontInfo(fInfo); { Need to get font's height and ascent. }
{ Horse the intersection of the clip and the box into the TE's viewRect
and then only draw at all if that rect is non empty }
IF SectRect(thePort^.clipRgn^^.rgnBBox, box, gMATextBoxTE^^.viewRect) THEN
BEGIN
WITH gMATextBoxTE^^, fInfo DO
BEGIN
destRect := box;
IF NOT spaceForCaret THEN { widen the destrect but not the visrect.
This lets the 1 pixel wide area to the
left of all text and the right of all text
go unshown. }
BEGIN
WITH destRect DO
BEGIN
left := left - kTextBoxCaretSlopSize;
right := right + kTextBoxCaretSlopSize;
END;
END;
{ Enforce minimum width on destRect ala IM-I pp. 383. Although the text says that
20 is a good number, using the widMax ensures that it is correct for all font sizes. }
WITH destRect DO
right := left + Max(Max(right - left, widMax), 20);
inPort := thePort; { Current port and its characteristics }
txSize := thePort^.txSize;
txFont := thePort^.txFont;
txFace := thePort^.txFace;
fontAscent := ascent;
lineHeight := ascent + descent + leading;
END;
TESetJust(itsJust, gMATextBoxTE); { be good, use the trap }
WITH gMATextBoxTE^^ DO
BEGIN
IF autoWrap THEN
crOnly := 0 {if >=0, word wrap}
ELSE
crOnly := - 1; {if <0, new line at Return only}
wordBreak := gTEDefaultWordBreak;
END;
IF wordBreak <> NIL THEN
SetWordBreak(wordBreak, gMATextBoxTE); { set the word break routine }
IF (pMATextBoxHText <> NIL) THEN { if our private heap is set up }
BEGIN
IF itsLength <= kOurMaxHandleSize THEN { short strings go in the mini-heap }
gMATextBoxTE^^.hText := pMATextBoxHText
ELSE
gMATextBoxTE^^.hText := pSaveHText;
END;
TESetText(text, Min(itsLength, kMaxTEChars), gMATextBoxTE);
{ if called with eraseFirst TRUE, then let TEUpdate image with its built-in EraseRect }
IF eraseFirst THEN
BEGIN
EraseRect(gMATextBoxTE^^.viewRect); { Oh yeah? Some versions of TE _DON'T_ erase first! }
TEUpdate(box, gMATextBoxTE);
END
ELSE
BEGIN
{ replace the existing QD procs ( standard or externally supplied )
so that the (<potential>, see comment above) EraseRect in TEUpdate is ignored }
IF thePort^.grafProcs <> NIL THEN
BEGIN
hadQDProcs := TRUE;
saveRectProc := thePort^.grafProcs^.rectProc;
thePort^.grafProcs^.rectProc := @StdNoRect;
END
ELSE
BEGIN
hadQDProcs := FALSE;
IF IsColorPort(thePort) THEN
BEGIN
SetStdCProcs(myCQDProcs);
myCQDProcs.rectProc := @StdNoRect;
thePort^.grafProcs := @myCQDProcs;
END
ELSE
BEGIN
SetStdProcs(myQDProcs);
myQDProcs.rectProc := @StdNoRect;
thePort^.grafProcs := @myQDProcs;
END;
END;
{ Now do the imaging }
TEUpdate(box, gMATextBoxTE);
{ Restore the QDProcs or eliminate the QDProcs, take yer pick. }
IF hadQDProcs THEN
thePort^.grafProcs^.rectProc := saveRectProc
ELSE
thePort^.grafProcs := NIL;
END;
END;
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
PROCEDURE MADrawString(s: StringPtr;
box: Rect;
justification: INTEGER);
VAR
theFontInfo: FontInfo;
widthOfString: INTEGER;
boxWidth: INTEGER;
BEGIN
GetFontInfo(theFontInfo);
widthOfString := StringWidth(s^);
WITH box DO
BEGIN
boxWidth := right - left;
IF widthOfString < boxWidth THEN
BEGIN
CASE GetActualJustification(justification) OF
teJustLeft: ;
teJustCenter:
left := left + (boxWidth - widthOfString) DIV 2;
teJustRight:
left := left + boxWidth - widthOfString;
teForceLeft: ;
END;
END;
MoveTo(left, top + theFontInfo.ascent);
DrawString(s^);
END;
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
FUNCTION PinOnRect(theRect: Rect;
thePt: Point): longint;
BEGIN
IF thePt.h < theRect.left THEN
thePt.h := theRect.left;
IF thePt.h > theRect.right THEN
thePt.h := theRect.right;
IF thePt.v < theRect.top THEN
thePt.v := theRect.top;
IF thePt.v > theRect.bottom THEN
thePt.v := theRect.bottom;
PinOnRect := longint(thePt);
END;
{--------------------------------------------------------------------------------------------------}
{$S WWSeg}
FUNCTION ReadInteger(prompt: Str255): INTEGER;
VAR
i: INTEGER;
BEGIN
{$IFC qDebug}
DebugForceOutput(forceOn, forceUnchanged);
{$EndC}
Write(prompt);
Readln(i);
{$IFC qDebug}
DebugEndForce;
{$EndC}
ReadInteger := i;
END;
{--------------------------------------------------------------------------------------------------}
{$S WWSeg}
FUNCTION ReadYesNo(prompt: Str255): Boolean;
VAR
s: Str255;
BEGIN
{$IFC qDebug}
DebugForceOutput(forceOn, forceUnchanged);
{$EndC}
Write(prompt);
Readln(s);
{$IFC qDebug}
DebugEndForce;
{$EndC}
ReadYesNo := (s <> '') & (s[1] IN ['y', 'Y']);
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
FUNCTION RectsNest(outer, inner: Rect): Boolean;
BEGIN
WITH inner DO
RectsNest := (left >= outer.left) & (right <= outer.right) & (top >= outer.top) & (bottom <=
outer.bottom);
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
FUNCTION VRectsNest(outer, inner: VRect): Boolean;
BEGIN
WITH inner DO
VRectsNest := (left >= outer.left) & (right <= outer.right) & (top >= outer.top) &
(bottom <= outer.bottom);
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
FUNCTION RoundUp(aNumber: longint;
aModulus: INTEGER): longint;
BEGIN
RoundUp := ((aNumber + aModulus - 1) DIV aModulus) * aModulus;
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
PROCEDURE ScrapStuffFields(aTitle: Str255;
VAR aScrapStuff: ScrapStuff;
PROCEDURE DoToField(fieldName: Str255;
fieldAddr: Ptr;
fieldType: INTEGER));
BEGIN
DoToField(aTitle, NIL, bTitle);
DoToField(' scrapSize', @aScrapStuff.scrapSize, bLongint);
DoToField(' scrapHandle', @aScrapStuff.scrapHandle, bHandle);
DoToField(' scrapCount', @aScrapStuff.scrapCount, bInteger);
DoToField(' scrapState', @aScrapStuff.scrapState, bInteger);
IF aScrapStuff.scrapName <> NIL THEN
DoToField(' scrapName', @aScrapStuff.scrapName^, bString)
ELSE
DoToField(' scrapName', NIL, bPointer);
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
FUNCTION SetKeyScript(newKeyScript: INTEGER): INTEGER;
VAR
currentKeyScript: INTEGER;
BEGIN
IF qNeedsScriptManager | gConfiguration.hasScriptManager THEN
BEGIN
currentKeyScript := GetEnvirons(smKeyScript);
IF currentKeyScript <> newKeyScript THEN
KeyScript(newKeyScript);
SetKeyScript := currentKeyScript;
END
ELSE
BEGIN
{ ??? what it the correct thing to do if we get here? }
END;
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes} {Must be in Main segment and cannot call to
any other segment.}
PROCEDURE SetHandleBits(h: Handle;
theBits: SignedByte);
BEGIN
IF qNeedsROM128K | gConfiguration.hasROM128K THEN
HSetState(h, theBits)
ELSE
SignedBytePtr(h)^ := theBits;
END;
{--------------------------------------------------------------------------------------------------}
{$IFC NOT qNeedsColorQD} { Becomes an inline if we know the machine
has color QD }
{$S MAUtilitiesRes}
PROCEDURE SetIfBkColor(aColor: RGBColor);
CONST
SignBit = 15;
VAR
index: INTEGER;
oldColor: longint;
BEGIN
IF qNeedsColorQD | gConfiguration.hasColorQD THEN
BEGIN
{ if not color port or color doesn't match then make trap }
WITH CGrafPtr(thePort)^ DO
IF (BAND(portVersion, $C000) <> $0000C000) | NOT EqualBlocks(@rgbBkColor, @aColor,
sizeof(RGBColor)) THEN
RGBBackColor(aColor);
END
ELSE
BEGIN
index := 0; { Prime index }
IF BTST(aColor.red, SignBit) THEN { Set bit if red >= $8000 }
index := 4;
IF BTST(aColor.green, SignBit) THEN { Set bit if green >= $8000 }
index := index + 2;
IF BTST(aColor.blue, SignBit) THEN { Set bit if blue >= $8000 }
index := index + 1;
CASE index OF
0:
oldColor := blackColor;
1:
oldColor := blueColor;
2:
oldColor := greenColor;
3:
oldColor := cyanColor;
4:
oldColor := redColor;
5:
oldColor := magentaColor;
6:
oldColor := yellowColor;
7:
oldColor := whiteColor;
END;
BackColor(oldColor);
END;
END;
{$ENDC}
{--------------------------------------------------------------------------------------------------}
{$IFC NOT qNeedsColorQD} { Becomes an inline if we know the machine
has color QD }
{$S MAUtilitiesRes}
PROCEDURE SetIfColor(aColor: RGBColor);
CONST
SignBit = 15;
VAR
index: INTEGER;
oldColor: longint;
BEGIN
IF qNeedsColorQD | gConfiguration.hasColorQD THEN
BEGIN
{ if not color port or color doesn't match then make trap }
WITH CGrafPtr(thePort)^ DO
IF (BAND(portVersion, $C000) <> $0000C000) | NOT EqualBlocks(@rgbFgColor, @aColor,
sizeof(RGBColor)) THEN
RGBForeColor(aColor);
END
ELSE
BEGIN
index := 0; { Prime index }
IF BTST(aColor.red, SignBit) THEN { Set bit if red >= $8000 }
index := 4;
IF BTST(aColor.green, SignBit) THEN { Set bit if green >= $8000 }
index := index + 2;
IF BTST(aColor.blue, SignBit) THEN { Set bit if blue >= $8000 }
index := index + 1;
CASE index OF
0:
oldColor := blackColor;
1:
oldColor := blueColor;
2:
oldColor := greenColor;
3:
oldColor := cyanColor;
4:
oldColor := redColor;
5:
oldColor := magentaColor;
6:
oldColor := yellowColor;
7:
oldColor := whiteColor;
END;
ForeColor(oldColor);
END;
END;
{$ENDC}
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
PROCEDURE GetPortTextStyle(VAR theTextStyle: TextStyle);
BEGIN
WITH thePort^, theTextStyle DO
BEGIN
tsFont := txFont;
tsFace := txFace;
tsSize := txSize;
GetIfColor(tsColor);
END;
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
PROCEDURE SetPortTextStyle(theTextStyle: TextStyle);
BEGIN
{ Don't make the traps unless we need to }
WITH thePort^, theTextStyle DO
BEGIN
IF txFont <> tsFont THEN
TextFont(tsFont);
IF txFace <> tsFace THEN
TextFace(tsFace);
IF txSize <> tsSize THEN
TextSize(tsSize);
SetIfColor(tsColor);
END;
END;
{--------------------------------------------------------------------------------------------------}
{$Push} { Must be in Main segment, and generic code,
because InitToolBox calls this }
{$MC68020-}
{$S MAUtilitiesRes}
PROCEDURE SetRGBColor(VAR RGB: RGBColor;
red, green, blue: INTEGER);
BEGIN
RGB.red := red;
RGB.green := green;
RGB.blue := blue;
END;
{$Pop}
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
PROCEDURE SetTextStyle(VAR theTextStyle: TextStyle;
theFont: INTEGER;
theStyle: Style;
theSize: INTEGER;
theColor: RGBColor);
BEGIN
WITH theTextStyle DO
BEGIN
tsFont := theFont;
tsFace := theStyle;
tsSize := theSize;
tsColor := theColor;
END;
END;
{--------------------------------------------------------------------------------------------------}
{$S MADebug}
PROCEDURE StdFieldToString(theData: Ptr;
fieldType: INTEGER;
VAR theString: Str255);
CONST
adnFrame = [adnLineTop, adnLineLeft, adnLineBottom, adnLineRight];
kDecPrec = 4; { Change this if you want more decimal
precision in extended}
TYPE
TAlias = RECORD
CASE INTEGER OF
bBoolean:
(asBoolean: Boolean);
bFontName, bCmdNumber, bHighByte, bLowByte, bHexInteger, bInteger:
(asInteger: INTEGER);
bFixed, bHexLongInt, bLongint:
(asLongInt: longint);
bString:
(asString: Str255);
bChar:
(asChar: CHAR);
bGrafPtr, bWindowPtr, bPointer:
(asPointer: Ptr);
bRgnHandle, bControlHandle, bTEHandle, bHandle:
(asHandle: Handle);
bPoint:
(asPoint: Point);
bRect:
(asRect: Rect);
bObject:
(asObject: Handle);
bByte:
(asByte: SignedByte);
bHLState:
(asHLState: SignedByte);
bIdType, bResType, bOSType:
(asOSType: OSType);
bPattern:
(asPattern: Pattern);
bRGBColor:
(asRGBColor: RGBColor);
bStyle:
(asStyle: Style);
bVCoordinate:
(asVCoordinate: VCoordinate);
bVPoint:
(asVPoint: VPoint);
bVRect:
(asVRect: VRect);
bStringHandle:
(asStrHandle: StringHandle);
bCntlAdornment:
(asCntlAdornment: CntlAdornment);
bSizeDeterminer:
(asSizeDeterminer: SignedByte);
bReal, bSingle:
(asReal: Real);
bDouble:
(asDouble: Double);
bExtended:
(asExtended: Extended);
bVHSelect:
(asVHSelect: VHSelect);
END;
VAR
alias: ^TAlias;
aString: Str255;
hexString: String8;
i: INTEGER;
{ Extended support }
aDecForm: DecForm;
x: Extended;
NumStr: DecStr;
PROCEDURE CheckStyleItem(s: StyleItem;
name: Str255);
BEGIN
IF s IN alias^.asStyle THEN
IF theString = '[' THEN
theString := CONCAT(theString, name)
ELSE
theString := CONCAT(theString, ',', name);
END;
PROCEDURE CheckAdornment(p: CntlAdornment;
name: Str255);
BEGIN
{ "set1 <= set2" means set1 is wholly contained in set2 }
IF p <= alias^.asCntlAdornment THEN
IF theString = '[' THEN
theString := CONCAT(theString, name)
ELSE
theString := CONCAT(theString, ',', name);
END;
BEGIN
alias := Pointer(theData);
theString := '';
WITH alias^ DO
CASE fieldType OF
bBoolean:
BEGIN
NumberToHex(asByte, theString, 2);
Insert(' (', theString, 1);
theString := CONCAT(theString, ')');
Insert(gBoolString[Ord(asBoolean) <> 0], theString, 1);
END;
bFontName:
GetFontName(asInteger, theString);
bInteger:
NumToString(asInteger, theString);
bLongint:
NumToString(asLongInt, theString);
bHexInteger:
NumberToHex(asInteger, theString, 4);
bHexLongInt:
NumberToHex(asLongInt, theString, 8);
bHighByte:
NumberToHex(BSR(BAND(asInteger, $FF00), 8), theString, 2);
bLowByte:
NumberToHex(BAND(asInteger, $00FF), theString, 2);
bFixed:
BEGIN
NumToString(HiWrd(asLongInt), aString);
NumToString(LoWrd(asLongInt), theString);
theString := CONCAT(aString, ':', theString);
END;
bString:
theString := asString;
bChar:
BEGIN
theString := ' ';
theString[1] := asChar;
END;
bGrafPtr, bWindowPtr, bPointer:
BEGIN
PointerToHex(ORD4(asPointer), aString, 8);
IF Odd(ORD4(asPointer)) THEN
theString := CONCAT('INVALID! (', aString, ')')
ELSE IF asHandle = NIL THEN
theString := 'Nil'
ELSE
theString := aString;
END;
bRgnHandle, bControlHandle, bTEHandle, bHandle:
BEGIN
PointerToHex(ORD4(asHandle), aString, 8);
IF Odd(ORD4(asHandle)) THEN
theString := CONCAT('INVALID! (', aString, ')')
ELSE IF asHandle = NIL THEN
theString := 'Nil'
ELSE
theString := aString;
END;
bPoint:
BEGIN
NumToString(asPoint.h, aString);
NumToString(asPoint.v, theString);
theString := CONCAT('(h:', aString, ', v:', theString, ')');
END;
bRect:
BEGIN
NumToString(asRect.left, aString);
NumToString(asRect.top, theString);
theString := CONCAT('(l:', aString, ', t:', theString, ')/(r:');
NumToString(asRect.right, aString);
theString := CONCAT(theString, aString, ', b:');
NumToString(asRect.bottom, aString);
theString := CONCAT(theString, aString, ')');
END;
bObject:
BEGIN
PointerToHex(ORD4(asObject), aString, 8);
IF Odd(ORD4(asObject)) THEN
theString := CONCAT('INVALID! (', aString, ')')
ELSE IF asObject = NIL THEN
theString := 'Nil'
ELSE
theString := aString;
END;
bByte:
NumToString(asByte, theString);
bHLState:
CASE asHLState OF
1:
theString := 'hlOff';
2:
theString := 'hlDim';
4:
theString := 'hlOn';
OTHERWISE
BEGIN
NumToString(asHLState, aString);
theString := CONCAT('INVALID! (', aString, ')');
END;
END;
bCmdNumber:
NumToString(asInteger, theString);
bIdType, bResType, bOSType:
BEGIN
theString := ''' ''';
FOR i := 1 TO 4 DO
theString[i + 1] := asOSType[i];
END;
bPattern:
BEGIN
theString := '$';
FOR i := 0 TO 7 DO
BEGIN
LIntToHex(asPattern[i], hexString, 2);
theString := CONCAT(theString, hexString);
END;
END;
bRGBColor:
WITH asRGBColor DO
IF (red = 0) & (green = 0) & (blue = 0) THEN
theString := 'Black'
ELSE IF (red = $FFFF) & (green = $FFFF) & (blue = $FFFF) THEN
theString := 'White'
ELSE
BEGIN
NumberToHex(asRGBColor.red, theString, 4);
NumberToHex(asRGBColor.green, aString, 4);
theString := CONCAT(theString, '/', aString);
NumberToHex(asRGBColor.blue, aString, 4);
theString := CONCAT(theString, '/', aString);
END;
bStyle:
BEGIN
theString := '[';
CheckStyleItem(bold, 'bold');
CheckStyleItem(italic, 'italic');
CheckStyleItem(underline, 'underline');
CheckStyleItem(outline, 'outline');
CheckStyleItem(shadow, 'shadow');
CheckStyleItem(condense, 'condense');
CheckStyleItem(extend, 'extend');
theString := CONCAT(theString, ']');
END;
bVCoordinate:
NumToString(asVCoordinate, theString);
bVPoint:
BEGIN
NumToString(asVPoint.h, aString);
NumToString(asVPoint.v, theString);
theString := CONCAT('(h:', aString, ', v:', theString, ')');
END;
bVRect:
BEGIN
NumToString(asVRect.left, aString);
NumToString(asVRect.top, theString);
theString := CONCAT('(l:', aString, ', t:', theString, ')/(r:');
NumToString(asVRect.right, aString);
theString := CONCAT(theString, aString, ', b:');
NumToString(asVRect.bottom, aString);
theString := CONCAT(theString, aString, ')');
END;
bStringHandle:
IF asStrHandle = NIL THEN
theString := 'Nil'
ELSE
theString := asStrHandle^^;
bCntlAdornment:
BEGIN
theString := '[';
IF adnFrame <= asCntlAdornment THEN
CheckAdornment(adnFrame, 'frame')
ELSE
BEGIN
CheckAdornment([adnLineTop], 'top');
CheckAdornment([adnLineLeft], 'left');
CheckAdornment([adnLineBottom], 'bottom');
CheckAdornment([adnLineRight], 'right');
END;
{ CheckAdornment(adnPatFill, 'fill'); }
CheckAdornment([adnOval], 'oval');
CheckAdornment([adnRRect], 'rrect');
CheckAdornment([adnShadow], 'shadow');
theString := CONCAT(theString, ']');
END;
bSizeDeterminer:
CASE asSizeDeterminer OF
0:
theString := 'sizeSuperView';
1:
theString := 'sizeRelSuperView';
2:
theString := 'sizePage';
3:
theString := 'sizeFillPages';
4:
theString := 'sizeVariable';
5:
theString := 'sizeFixed';
END;
bReal, bSingle:
BEGIN
aDecForm.Style := FixedDecimal;
aDecForm.digits := kDecPrec;
x := asReal;
Num2Str(aDecForm, x, NumStr);
theString := Str255(NumStr);
END;
bDouble:
BEGIN
aDecForm.Style := FixedDecimal;
aDecForm.digits := kDecPrec;
x := asDouble;
Num2Str(aDecForm, x, NumStr);
theString := Str255(NumStr);
END;
bExtended:
BEGIN
aDecForm.Style := FixedDecimal;
aDecForm.digits := kDecPrec;
x := asExtended;
Num2Str(aDecForm, x, NumStr);
theString := Str255(NumStr);
END;
bVHSelect:
BEGIN
CASE asVHSelect OF
v:
theString := 'v';
h:
theString := 'h';
OTHERWISE
BEGIN
NumToString(ORD(asVHSelect), aString);
theString := CONCAT('INVALID! (', aString, ')');
END;
END;
END;
END;
END;
{--------------------------------------------------------------------------------------------------}
FUNCTION StripLong(address: UNIV Ptr): longint;
EXTERNAL;
{--------------------------------------------------------------------------------------------------}
{$S MAFields}
PROCEDURE TextStyleFields(aTitle: Str255;
VAR aStyle: TextStyle;
PROCEDURE DoToField(fieldName: Str255;
fieldAddr: Ptr;
fieldType: INTEGER));
BEGIN
DoToField(aTitle, NIL, bTitle);
DoToField(' Font', @aStyle.tsFont, bFontName);
DoToField(' Face', @aStyle.tsFace, bStyle);
DoToField(' Size', @aStyle.tsSize, bInteger);
DoToField(' Color', @aStyle.tsColor, bRGBColor);
END;
{--------------------------------------------------------------------------------------------------}
{$Push}
{$MC68020-}
{$S MAUtilitiesRes}
FUNCTION NumToolboxTraps: INTEGER;
{ InitGraf is always implemented (trap $A86E). If the trap table is big enough, trap $AA6E
will always point to either Unimplemented or some other trap, but will never be the same
as InitGraf. Thus, you can check the size of the trap table by asking if the address of
trap $A86E is the same as $AA6E. }
BEGIN
IF NGetTrapAddress(_InitGraf, ToolTrap) = NGetTrapAddress($AA6E, ToolTrap) THEN
NumToolboxTraps := $200
ELSE
NumToolboxTraps := $400;
END;
{$Pop}
{--------------------------------------------------------------------------------------------------}
{$Push}
{$MC68020-}
{$S MAUtilitiesRes}
FUNCTION TrapExists(theTrap: INTEGER): Boolean;
{ Thank-you François Grieu! }
CONST
UnimNb = _Unimplemented-$A800; {Trap NUMBER of an unimplemented Tool trap}
VAR
theTrapType: TrapType;
BEGIN
{ this is a safety check, for debug mode }
IF qDebug THEN
IF BAND(theTrap,$0A000)<>$0A000 THEN
BEGIN
WrLblHexInt('TrapExists wants trap WORDs, not ', theTrap);
WriteLn;
ProgramBreak('');
END;
{ here theTrap is a trap WORD }
theTrapType := GetTrapType(theTrap); { decide from bit 11 if trap is a Tool or OS trap }
IF (theTrapType = OsTrap) THEN
theTrap := BAND(theTrap, $00FF)
ELSE
BEGIN
theTrap := BAND(theTrap, $03FF);
IF theTrap >= NumToolboxTraps THEN
theTrap := UnimNb;
END;
{ here theTrap has been converted a trap NUMBER }
{ on 64K ROM machines, we need to check that the trap number matches the trap type }
IF (NOT qNeedsROM128k) & (NOT gConfiguration.hasROM128k) THEN
IF ((theTrap<$050) | (theTrap=$054) | (theTrap=$057)) <> (theTrapType = OsTrap) THEN
theTrap := UnimNb;
{ finaly check if the trap has the same address has the Unimplemented trap. }
{ note that we pass GetTrapAddress a trap NUMBER, as documented, not a trap WORD }
TrapExists := NGetTrapAddress(UnimNb, ToolTrap) <>
NGetTrapAddress(theTrap, theTrapType);
END;
{$Pop}
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
FUNCTION UprChar(ch: CHAR): CHAR;
BEGIN
IF (ch IN ['a'..'z']) THEN
UprChar := CHR(Ord(ch) - 32)
ELSE
UprChar := ch;
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
PROCEDURE UprStr255(VAR s: Str255);
VAR
i: INTEGER;
BEGIN
FOR i := 1 TO LENGTH(s) DO
IF (s[i] IN ['a'..'z']) THEN
s[i] := CHR(Ord(s[i]) - 32)
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
PROCEDURE UprMAName(VAR s: MAName);
VAR
i: INTEGER;
BEGIN
FOR i := 1 TO LENGTH(s) DO
IF (s[i] IN ['a'..'z']) THEN
s[i] := CHR(Ord(s[i]) - 32)
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
PROCEDURE UseROMMap(resLoad: Boolean);
BEGIN
IF qNeedsROM128K | gConfiguration.hasROM128K THEN
BEGIN
IF resLoad THEN
GetROMMapInsert^ := kLMmapTrue
ELSE
GetROMMapInsert^ := kLMmapFalse;
END
ELSE
SetResLoad(resLoad);
END;
{--------------------------------------------------------------------------------------------------}
{$S MADebug}
FUNCTION VerboseIsHandle(h: UNIV Handle): Boolean;
CONST
kUnInitStorage1 = $72677267; { Pascal provided uninited storage }
kUnInitStorage2 = $67726772; { odd byte boundary of above }
kDebugHandleInit = $F3F3F3F3; { Handles are inited to this in MacApp® }
kDebugPtrInit = $F5F5F5F5; { Pointers are inited to this in MacApp® }
kDebugObjInit = $F1F1F1F1; { Objects are inited to this in MacApp® }
VAR
masterPointer: Ptr;
BEGIN
VerboseIsHandle := FALSE;
IF Odd(Ord(h)) THEN
BEGIN
IF Ord(h) = kUnInitStorage1 THEN
WriteLn(' That handle appears to be from uninitialized storage.')
ELSE IF (Ord(h) = kDebugHandleInit) THEN
WriteLn(' That handle appears to be from a handle initialized by debugging.')
ELSE IF (Ord(h) = kDebugPtrInit) THEN
WriteLn(' That handle appears to be from a pointer initialized by debugging.')
ELSE IF (Ord(h) = kDebugObjInit) THEN
WriteLn(' That handle appears to be an uninitialized instance variable.')
ELSE
WriteLn(' That handle is odd.');
END
ELSE IF Ord(h) = kUnInitStorage2 THEN
WriteLn(' That handle appears to be from uninitialized storage.')
ELSE IF h = NIL THEN
WriteLn(' That handle is NIL.')
ELSE
BEGIN
masterPointer := Ptr(StripLong(h^));
IF Odd(Ord(masterPointer)) THEN
WriteLn(' The master pointer is odd.')
ELSE IF IsFreeHandle(h) THEN
WriteLn(' The handle has been freed.')
ELSE IF ((masterPointer <> NIL) & NOT TestRecoverHandle(masterPointer, h)) THEN
WriteLn(' The alleged heap header is invalid.')
ELSE
VerboseIsHandle := TRUE;
END;
END;
{--------------------------------------------------------------------------------------------------}
{$S MAUtilitiesRes}
PROCEDURE WithApplicationResFileDo(PROCEDURE DoWithResFile);
{??? Needs a failure handler ???}
VAR
oldResFile: INTEGER;
BEGIN
oldResFile := CurResFile;
UseResFile(gApplicationRefNum);
DoWithResFile;
UseResFile(oldResFile);
END;
{--------------------------------------------------------------------------------------------------}
{$S WWSeg}
PROCEDURE WriteHandleContents(theHandle: UNIV Handle);
VAR
Max, index: Size;
wasLocked: Boolean;
BEGIN
Max := GetHandleSize(theHandle) - 1;
IF Max > 0 THEN
BEGIN
wasLocked := IsHandleLocked(theHandle);
IF NOT wasLocked THEN
HLock(theHandle);
FOR index := 0 TO Max DO
Write(CHR(Ptr(Ord(theHandle^) + index)^));
IF NOT wasLocked THEN
HUnLock(theHandle);
END
ELSE
Write('**Empty**');
END;
{--------------------------------------------------------------------------------------------------}
{$S WWSeg}
PROCEDURE WrLblHandleContents(aLabel: Str255;
theHandle: UNIV Handle);
BEGIN
Write(aLabel, ' = '); WriteHandleContents(theHandle);
END;
{--------------------------------------------------------------------------------------------------}
{$S WWSeg}
PROCEDURE WritePt(pt: Point);
VAR
theString: Str255;
BEGIN
FieldToString(@pt, bPoint, theString);
Write(theString);
END;
{--------------------------------------------------------------------------------------------------}
{$S WWSeg}
PROCEDURE WrLblPt(aLabel: Str255;
pt: Point);
BEGIN
Write(aLabel, ' = '); WritePt(pt);
END;
{--------------------------------------------------------------------------------------------------}
{$S WWSeg}
PROCEDURE WritePtr(val: UNIV longint);
VAR
theString: Str255;
BEGIN
FieldToString(@val, bPointer, theString);
Write(theString);
END;
{--------------------------------------------------------------------------------------------------}
{$S WWSeg}
PROCEDURE WrLblPtr(aLabel: Str255;
val: UNIV longint);
BEGIN
Write(aLabel, ' = '); WritePtr(val);
END;
{--------------------------------------------------------------------------------------------------}
{$S WWSeg}
PROCEDURE WriteRect(r: Rect);
VAR
theString: Str255;
BEGIN
FieldToString(@r, bRect, theString);
Write(theString);
END;
{--------------------------------------------------------------------------------------------------}
{$S WWSeg}
PROCEDURE WrLblRect(aLabel: Str255;
r: Rect);
BEGIN
Write(aLabel, ' = '); WriteRect(r);
END;
{--------------------------------------------------------------------------------------------------}
{$S WWSeg}
PROCEDURE WriteBoolean(b: Boolean);
VAR
theString: Str255;
BEGIN
FieldToString(@b, bBoolean, theString);
Write(theString);
END;
{--------------------------------------------------------------------------------------------------}
{$S WWSeg}
PROCEDURE WrLblBoolean(aLabel: Str255;
b: Boolean);
BEGIN
Write(aLabel, ' = ');
WriteBoolean(b);
END;
{--------------------------------------------------------------------------------------------------}
{$S WWSeg}
PROCEDURE WriteVPt(pt: VPoint);
VAR
theString: Str255;
BEGIN
FieldToString(@pt, bVPoint, theString);
Write(theString);
END;
{--------------------------------------------------------------------------------------------------}
{$S WWSeg}
PROCEDURE WrLblVPt(aLabel: Str255;
pt: VPoint);
BEGIN
Write(aLabel, ' = '); WriteVPt(pt);
END;
{--------------------------------------------------------------------------------------------------}
{$S WWSeg}
PROCEDURE WriteVRect(r: VRect);
VAR
theString: Str255;
BEGIN
FieldToString(@r, bVRect, theString);
Write(theString);
END;
{--------------------------------------------------------------------------------------------------}
{$S WWSeg}
PROCEDURE WrLblVRect(aLabel: Str255;
r: VRect);
BEGIN
Write(aLabel, ' = '); WriteVRect(r);
END;
{--------------------------------------------------------------------------------------------------}
{$S WWSeg}
PROCEDURE WriteSig(theID: IDType);
VAR
theString: Str255;
BEGIN
FieldToString(@theID, bIdType, theString);
Write(theString);
END;
{--------------------------------------------------------------------------------------------------}
{$S WWSeg}
PROCEDURE WrLblSig(theLabel: Str255;
theID: IDType);
BEGIN
Write(theLabel, ' = '); WriteSig(theID);
END;
{--------------------------------------------------------------------------------------------------}
{$S WWSeg}
PROCEDURE WriteHexInt(theInt: INTEGER);
VAR
theString: Str255;
BEGIN
FieldToString(@theInt, bHexInteger, theString);
Write(theString);
END;
{--------------------------------------------------------------------------------------------------}
{$S WWSeg}
PROCEDURE WrLblHexInt(theLabel: Str255;
theInt: INTEGER);
BEGIN
Write(theLabel, ' = '); WriteHexInt(theInt);
END;
{--------------------------------------------------------------------------------------------------}
{$S WWSeg}
PROCEDURE WriteHexLongint(theLongint: longint);
VAR
theString: Str255;
BEGIN
FieldToString(@theLongint, bHexLongInt, theString);
Write(theString);
END;
{--------------------------------------------------------------------------------------------------}
{$S WWSeg}
PROCEDURE WrLblHexLongint(theLabel: Str255;
theLongint: longint);
BEGIN
Write(theLabel, ' = '); WriteHexLongint(theLongint);
END;